

#include "Drivers\Drivers.h"
#include "ESS_CommonDefine.h"
#include "ESS_MainSystemConfigDefine.h"
#include  "PackInfor\PackInformationFunctions.h"


//////////////////////////////////////////////////////////////////////////////
// for calculating System Avg current 
#define Avg_array_size  8
typedef struct {
  int Values[Avg_array_size];
  unsigned int index; 
  unsigned char filledOnceFlag;
} CurrentStruct;
CurrentStruct ModuleCurrent;
/////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////


/////////////////////////////////////////////
// for Communication Indication 
unsigned char G_Indication_Comm_Failure_M1;
unsigned char G_Indication_Comm_Failure_M2;
unsigned char G_Indication_Comm_Failure_M3;
/////////////////////////////////////////////
// only for SOH1 and SOH2 Indication 
unsigned char G_Indication_SOH_Failure_M1;
unsigned char G_Indication_SOH_Failure_M2;
unsigned char G_Indication_SOH_Failure_M3;

unsigned char G_Indication_FCC_Failure_M1;
unsigned char G_Indication_FCC_Failure_M2;
unsigned char G_Indication_FCC_Failure_M3;

unsigned char G_Indication_CycleCount_Failure_M1;
unsigned char G_Indication_CycleCount_Failure_M2;
unsigned char G_Indication_CycleCount_Failure_M3;
//////////////////////////////////////////////////////
// only for Pack FET Control status Indication
// turn on = 1, turn off = 0.
unsigned char G_Indication_DSGFET_M1;
unsigned char G_Indication_DSGFET_M2;
unsigned char G_Indication_DSGFET_M3;

unsigned char G_Indication_CHGFET_M1;
unsigned char G_Indication_CHGFET_M2;
unsigned char G_Indication_CHGFET_M3;
//////////////////////////////////////////////////////

void InitSystemInfo(){
  unsigned int loop_i;
  ModuleCurrent.index = 0;
  ModuleCurrent.filledOnceFlag = false;
  for(loop_i = 0; loop_i < Avg_array_size; loop_i++){
    ModuleCurrent.Values[loop_i] = 0;
  }
  //G_Module_Status = 0;
  /////////////////////////////////////////////
  // for Communication Indication 
  G_Indication_Comm_Failure_M1 = 0;
  G_Indication_Comm_Failure_M2 = 0;
  G_Indication_Comm_Failure_M3 = 0;
  /////////////////////////////////////////////
  // only for SOH1 and SOH2 Indication 
  G_Indication_SOH_Failure_M1 = 0;
  G_Indication_SOH_Failure_M2 = 0;
  G_Indication_SOH_Failure_M3 = 0;
  G_Indication_FCC_Failure_M1 = 0;
  G_Indication_FCC_Failure_M2 = 0;
  G_Indication_FCC_Failure_M3 = 0;
  G_Indication_CycleCount_Failure_M1 = 0;
  G_Indication_CycleCount_Failure_M2 = 0;
  G_Indication_CycleCount_Failure_M3 = 0;
  //////////////////////////////////////////////////////
  // only for Pack FET Control status Indication
  // turn on = 1, turn off = 0.
  G_Indication_DSGFET_M1 = 0;
  G_Indication_DSGFET_M2 = 0;
  G_Indication_DSGFET_M3 = 0;
  G_Indication_CHGFET_M1 = 0;
  G_Indication_CHGFET_M2 = 0;
  G_Indication_CHGFET_M3 = 0;  
}

void setSystemCurrentToAvgArray( int current){
  ModuleCurrent.Values[ModuleCurrent.index] = current;
  ModuleCurrent.index++;
  if(ModuleCurrent.index >= Avg_array_size){
    ModuleCurrent.index = 0;
    ModuleCurrent.filledOnceFlag = true;
  }
}
int getAvgSystemCurrent(){
  long total;
  unsigned int loop_i;
  total = 0;
  if(ModuleCurrent.filledOnceFlag){
    for(loop_i = 0; loop_i < Avg_array_size; loop_i++){
      total += ModuleCurrent.Values[loop_i];
    }
    return (int)(total >> 3); //=total/8
    //return (int)(total/Avg_array_size);
  }else{
    for(loop_i = 0; loop_i < ModuleCurrent.index; loop_i++){
      total += ModuleCurrent.Values[loop_i];
    }
    return (int)(total/ModuleCurrent.index);
  }
}




long getModuleCurrent(unsigned char module_Num){

  int pack_, values;
  long total;
  unsigned char count = 0;
  values = 0;
  total = 0;
  
  for(pack_ = 0; pack_< NumOfParallelPacks; pack_++){
	  if(module[module_Num].pack[pack_].packInfoFail[current] == PackNormal){
      values = module[module_Num].pack[pack_].packInfo[current][1] << 8;
      values |= module[module_Num].pack[pack_].packInfo[current][0];
      total += values;
	  	count++;
	  }
	}
  return total;
  
}

int calculateSystemCurrent(){
  long systemCurrent = 0;
  unsigned char loop_Module;
    
    for(loop_Module = _M1; loop_Module <= _M3; loop_Module++){
      systemCurrent += getModuleCurrent(loop_Module);
    }

		return (systemCurrent / 3);
}

unsigned int getModuleVoltage(char module_Num){

  unsigned int pack_, values;
  unsigned long total;
  unsigned char count = 0;
  values = 0;
  total = 0;
  
  for(pack_ = 0; pack_< NumOfParallelPacks; pack_++){
	  if(module[module_Num].pack[pack_].packInfoFail[voltage] == PackNormal){
      values = module[module_Num].pack[pack_].packInfo[voltage][1] << 8;
      values |= module[module_Num].pack[pack_].packInfo[voltage][0];
      total += values;
	  	count++;
	  }
	}
	if(count > 0){
		return (unsigned int)(total / count);
	}else{
		return (unsigned int)total;
	}
}

unsigned int calculateSystemVoltage(){
  unsigned long systemVoltage = 0;
  unsigned char loop_Module;
    
    for(loop_Module = _M1; loop_Module <= _M3; loop_Module++){
      systemVoltage += getModuleVoltage(loop_Module);
    }
		return (unsigned int)systemVoltage;
}

/////////////////////////////////////////////////////////////////////////////
// compare for FCC (FullChargeCapacity) and Ctcle count, create at 2011/07/25
void SystemPackSOHInformationUpdate(unsigned char moduleName, unsigned char packNum, unsigned char PackFailFalg){
  unsigned int FCCValue, CycleCountValue;
  
  if(PackFailFalg){
    setPackSOHFailure(moduleName, packNum, false);
    setPackFCCFailure(moduleName, packNum, false);
    setPackCycleCountFailure(moduleName, packNum, false);
    return;
  }
  
  FCCValue = module[moduleName].pack[packNum].packInfo[fullChargeCapacity][1] << 8;
  FCCValue |= module[moduleName].pack[packNum].packInfo[fullChargeCapacity][0];
  
  CycleCountValue = module[moduleName].pack[packNum].packInfo[cycleCount][1] << 8;
  CycleCountValue |= module[moduleName].pack[packNum].packInfo[cycleCount][0];

  if(FCCValue < FCC_Failure_Threshold || CycleCountValue > CycleCounts_Failure_Threshold){
    setPackSOHFailure(moduleName, packNum, true);
  }else{
    setPackSOHFailure(moduleName, packNum, false);
  }
  if(FCCValue < FCC_Failure_Threshold){
    setPackFCCFailure(moduleName, packNum, true);
  }else{
    setPackFCCFailure(moduleName, packNum, false);
  }
  if(CycleCountValue > CycleCounts_Failure_Threshold){
    setPackCycleCountFailure(moduleName, packNum, true);
  }else{
    setPackCycleCountFailure(moduleName, packNum, false);
  }

}//void PackSOHInformationUpdate(){
//////////////////////////////////////////////////////////////////////////////
// G_Indication_Comm_Failure_Mx : 
// using bit0~bit5 represent Pack _A~_F fail
void setPackCommunicationFailure(unsigned char moduleName, unsigned char packName, unsigned char failureFlag){
  unsigned char databit;
  databit = 1;
  databit = databit << packName;
  
  switch(moduleName){
    case _M1:
      if(failureFlag){
        G_Indication_Comm_Failure_M1 |=  databit;
      }else{
        G_Indication_Comm_Failure_M1 &=  ~databit;
      }
      break;
    case _M2:
      if(failureFlag){
        G_Indication_Comm_Failure_M2 |=  databit;
      }else{
        G_Indication_Comm_Failure_M2 &=  ~databit;
      }
      break;
    case _M3:
      if(failureFlag){
        G_Indication_Comm_Failure_M3 |=  databit;
      }else{
        G_Indication_Comm_Failure_M3 &=  ~databit;
      }
      break;
  }
  
  UpdatedModuleStatusForSeriesBlockOccursFailure();
}
//////////////////////////////////////////////////////////////////////////////
// G_Indication_SOH_Failure_Mx : 
// using bit0~bit5 represent Pack _A~_F fail
void setPackSOHFailure(unsigned char moduleName, unsigned char packName, unsigned char failureFlag){
  unsigned char databit;
  databit = 1;
  databit = databit << packName;
  
    switch(moduleName){
      case _M1:
        if(failureFlag){
          G_Indication_SOH_Failure_M1 |=  databit;
        }else{
          G_Indication_SOH_Failure_M1 &=  ~databit;
        }
        break;
      case _M2:
        if(failureFlag){
          G_Indication_SOH_Failure_M2 |=  databit;
        }else{
          G_Indication_SOH_Failure_M2 &=  ~databit;
        }
        break;
      case _M3:
        if(failureFlag){
          G_Indication_SOH_Failure_M3 |=  databit;
        }else{
          G_Indication_SOH_Failure_M3 &=  ~databit;
        }
        break;
    }
//    if(G_Indication_SOH_Failure_M1 > 0 || G_Indication_SOH_Failure_M2 > 0 || G_Indication_SOH_Failure_M3 > 0){
//      setLEDsOnOff(Yellow_LED, true);
//    }else{
//      setLEDsOnOff(Yellow_LED, false);
//    }
}
//////////////////////////////////////////////////////////////////////////////
// G_Indication_FCC_Failure_Mx : 
// using bit0~bit5 represent Pack _A~_F fail
void setPackFCCFailure(unsigned char moduleName, unsigned char packName, unsigned char failureFlag){
  unsigned char databit;
  databit = 1;
  databit = databit << packName;
  
    switch(moduleName){
      case _M1:
        if(failureFlag){
          G_Indication_FCC_Failure_M1 |=  databit;
        }else{
          G_Indication_FCC_Failure_M1 &=  ~databit;
        }
        break;
      case _M2:
        if(failureFlag){
          G_Indication_FCC_Failure_M2 |=  databit;
        }else{
          G_Indication_FCC_Failure_M2 &=  ~databit;
        }
        break;
      case _M3:
        if(failureFlag){
          G_Indication_FCC_Failure_M3 |=  databit;
        }else{
          G_Indication_FCC_Failure_M3 &=  ~databit;
        }
        break;
    }
    if(G_Indication_FCC_Failure_M1 > 0 || G_Indication_FCC_Failure_M2 > 0 || G_Indication_FCC_Failure_M3 > 0){
      G_Module_Status |= SOH1;
    }else{
      G_Module_Status &= ~SOH1;
    }
}
//////////////////////////////////////////////////////////////////////////////
// G_Indication_CycleCountFailure_Mx : 
// using bit0~bit5 represent Pack _A~_F fail
void setPackCycleCountFailure(unsigned char moduleName, unsigned char packName, unsigned char failureFlag){
  unsigned char databit;
  databit = 1;
  databit = databit << packName;
  
    switch(moduleName){
      case _M1:
        if(failureFlag){
          G_Indication_CycleCount_Failure_M1 |=  databit;
        }else{
          G_Indication_CycleCount_Failure_M1 &=  ~databit;
        }
        break;
      case _M2:
        if(failureFlag){
          G_Indication_CycleCount_Failure_M2 |=  databit;
        }else{
          G_Indication_CycleCount_Failure_M2 &=  ~databit;
        }
        break;
      case _M3:
        if(failureFlag){
          G_Indication_CycleCount_Failure_M3 |=  databit;
        }else{
          G_Indication_CycleCount_Failure_M3 &=  ~databit;
        }
        break;
    }
    if(G_Indication_CycleCount_Failure_M1 > 0 || G_Indication_CycleCount_Failure_M2 > 0 || G_Indication_CycleCount_Failure_M3 > 0){
      G_Module_Status |= SOH2;
    }else{
      G_Module_Status &= ~SOH2;
    }
}
//////////////////////////////////////////////////////////////////////////////
// SET  PackFETStatus by Pack FET control register
// bit1 = DSG MosFET, bit2 = CHG MosFET
void setPackFETStatus(unsigned char moduleName, unsigned char packName, unsigned char FETControl){
  unsigned char databit, dsg, chg;
  databit = 1;
  databit = databit << packName;
  
  dsg = FETControl & PackFETDSGBit;
  chg = FETControl & PackFETCHGBit;
  
    switch(moduleName){
      case _M1:
        if(dsg){
          G_Indication_DSGFET_M1 |=  databit;
        }else{
          G_Indication_DSGFET_M1 &=  ~databit;
        }
        if(chg){
          G_Indication_CHGFET_M1 |=  databit;
        }else{
          G_Indication_CHGFET_M1 &=  ~databit;
        }
        break;
      case _M2:
        if(dsg){
          G_Indication_DSGFET_M2 |=  databit;
        }else{
          G_Indication_DSGFET_M2 &=  ~databit;
        }
        if(chg){
          G_Indication_CHGFET_M2 |=  databit;
        }else{
          G_Indication_CHGFET_M2 &=  ~databit;
        }
        break;
      case _M3:
        if(dsg){
          G_Indication_DSGFET_M3 |=  databit;
        }else{
          G_Indication_DSGFET_M3 &=  ~databit;
        }
        if(chg){
          G_Indication_CHGFET_M3 |=  databit;
        }else{
          G_Indication_CHGFET_M3 &=  ~databit;
        }
        break;
    }
    UpdatedModuleStatusForSeriesBlockOccursFailure();
    
}

void UpdatedModuleStatusForSeriesBlockOccursFailure(){
  
  unsigned char dsg,chg;
  
  dsg = (~G_Indication_DSGFET_M1) & 0x3f;
  chg = (~G_Indication_CHGFET_M1) & 0x3f;
  
  if(dsg || chg || G_Indication_Comm_Failure_M1){
    G_Module_Status |= S1;
  }else{
    G_Module_Status &= ~S1;
  }
  
  dsg = (~G_Indication_DSGFET_M2) & 0x3f;
  chg = (~G_Indication_CHGFET_M2) & 0x3f;
  
  if(dsg || chg || G_Indication_Comm_Failure_M2){
    G_Module_Status |= S2;
  }else{
    G_Module_Status &= ~S2;
  }
  
  dsg = (~G_Indication_DSGFET_M3) & 0x3f;
  chg = (~G_Indication_CHGFET_M3) & 0x3f;
  
  if(dsg || chg || G_Indication_Comm_Failure_M3){
    G_Module_Status |= S3;
  }else{
    G_Module_Status &= ~S3;
  } 
}

void CheckSystemOnePackFailureAndSOHForLEDLighting(){
	////////////////////////////////////
	// set LED Blink
  if(G_Indication_DSGFET_M1 != 0x3f ||
     G_Indication_DSGFET_M2 != 0x3f ||
     G_Indication_DSGFET_M3 != 0x3f ||
     G_Indication_CHGFET_M1 != 0x3f ||
     G_Indication_CHGFET_M2 != 0x3f ||
     G_Indication_CHGFET_M3 != 0x3f ||
     G_Indication_Comm_Failure_M1 != 0x00 ||
     G_Indication_Comm_Failure_M2 != 0x00 ||
     G_Indication_Comm_Failure_M3 != 0x00 ||
     (G_Module_Status & OTA) != 0)
  {
      set_Blinking_Function(Red_LED, true); 
  }else{
    set_Blinking_Function(Red_LED, false);  
  }

  if(G_Indication_SOH_Failure_M1 > 0 || G_Indication_SOH_Failure_M2 > 0 || G_Indication_SOH_Failure_M3 > 0){
    setLEDsOnOff(Yellow_LED, true);
  }else{
    setLEDsOnOff(Yellow_LED, false);
  }
}
#define CalibrationADCArraySize   4
unsigned int ADG80_ADCArray[CalibrationADCArraySize];
unsigned int CHG_OPA_ADCArray[CalibrationADCArraySize];
unsigned int DSG_OPA_ADCArray[CalibrationADCArraySize];
unsigned char g_CalADCArrayIndex;

void initADCCurrentAvgArray(){
  unsigned char loop_i;
  for(loop_i=0; loop_i < CalibrationADCArraySize; loop_i++){
    ADG80_ADCArray[loop_i] = 0;
    CHG_OPA_ADCArray[loop_i] = 0;
    DSG_OPA_ADCArray[loop_i] = 0;
  }
  g_CalADCArrayIndex = 0;
}

void setADCCurrentToAvgArray( unsigned int ADG80_ADC, unsigned int CHG_OPA_ADC, unsigned int DSG_OPA_ADC){
  
  ADG80_ADCArray[g_CalADCArrayIndex] = ADG80_ADC;
  CHG_OPA_ADCArray[g_CalADCArrayIndex] = CHG_OPA_ADC;
  DSG_OPA_ADCArray[g_CalADCArrayIndex] = DSG_OPA_ADC;
  g_CalADCArrayIndex++;
  if(g_CalADCArrayIndex >= CalibrationADCArraySize){
    g_CalADCArrayIndex = 0;
  }
}

unsigned int getADG80_ADCAvgValFromArray(){
  unsigned int i;
  unsigned int avg;
  i = 0;
  avg = 0;
  for(i=0; i < CalibrationADCArraySize; i++){
    avg += ADG80_ADCArray[i];
  }
  avg = avg >> 2;
  return avg;
}
unsigned int getCHG_OPA_ADCAvgValFromArray(){
  unsigned int i;
  unsigned int avg;
  i = 0;
  avg = 0;
  for(i=0; i < CalibrationADCArraySize; i++){
    avg += CHG_OPA_ADCArray[i];
  }
  avg = avg >> 2;
  return avg;
}
unsigned int getDSG_OPA_ADCAvgValFromArray(){
  unsigned int i;
  unsigned int avg;
  i = 0;
  avg = 0;
  for(i=0; i < CalibrationADCArraySize; i++){
    avg += DSG_OPA_ADCArray[i];
  }
  avg = avg >> 2;
  return avg;
}
